#include "XTimeAdapter.h"
#include <ctime>

namespace Xts
{
	namespace Util
	{
		XTimezoneDateTime::XTimezoneDateTime(const Ice::Short& year, const Ice::Short& month, const Ice::Short& day,
			const Ice::Short& hour, const Ice::Short& minute, const Ice::Short& second,
			const Ice::Short& milisec, const Ice::Short& microsec, const Ice::Long& timezoneInterval)
			:x_year(year), x_month(month), x_day(day), x_hour(hour), x_minute(minute), x_second(second),
			x_milisec(milisec), x_microsec(microsec), x_timezoneInterval(timezoneInterval)
		{}

		XTimezoneDateTime::XTimezoneDateTime(const Ice::Short& year, const Ice::Short& month, const Ice::Short& day,
			const Ice::Short& hour, const Ice::Short& minute, const Ice::Short& second,
			const Ice::Short& milisec, const Ice::Short& microsec, XTimeZone timeZone)
			: x_year(year), x_month(month), x_day(day), x_hour(hour), x_minute(minute), x_second(second),
			x_milisec(milisec), x_microsec(microsec), x_timezoneInterval(GetTimeZoneInterval(timeZone))
		{}

		Ice::Long XTimezoneDateTime::GetTimeZoneInterval(XTimeZone timeZone)
		{
			Ice::Long timezoneInterval = 0;
			switch (timeZone)
			{
			case Xts::Util::UTC000:
				return timezoneInterval = 0;
				break;
			case Xts::Util::UTCE01:
				timezoneInterval = -1 * 3600;
				break;
			case Xts::Util::UTCE02:
				timezoneInterval = -2 * 3600;
				break;
			case Xts::Util::UTCE03:
				timezoneInterval = -3 * 3600;
				break;
			case Xts::Util::UTCE04:
				timezoneInterval = -4 * 3600;
				break;
			case Xts::Util::UTCE05:
				timezoneInterval = -5 * 3600;
				break;
			case Xts::Util::UTCE06:
				timezoneInterval = -6 * 3600;
				break;
			case Xts::Util::UTCE07:
				timezoneInterval = -7 * 3600;
				break;
			case Xts::Util::UTCE08:
				timezoneInterval = -8 * 3600;
				break;
			case Xts::Util::UTCE09:
				timezoneInterval = -9 * 3600;
				break;
			case Xts::Util::UTCE10:
				timezoneInterval = -10 * 3600;
				break;
			case Xts::Util::UTCE11:
				timezoneInterval = -11 * 3600;
				break;
			case Xts::Util::UTCE12:
				timezoneInterval = -12 * 3600;
				break;
			case Xts::Util::UTCW01:
				timezoneInterval = 1 * 3600;
				break;
			case Xts::Util::UTCW02:
				timezoneInterval = 2 * 3600;
				break;
			case Xts::Util::UTCW03:
				timezoneInterval = 3 * 3600;
				break;
			case Xts::Util::UTCW04:
				timezoneInterval = 4 * 3600;
				break;
			case Xts::Util::UTCW05:
				timezoneInterval = 5 * 3600;
				break;
			case Xts::Util::UTCW06:
				timezoneInterval = 6 * 3600;
				break;
			case Xts::Util::UTCW07:
				timezoneInterval = 7 * 3600;
				break;
			case Xts::Util::UTCW08:
				timezoneInterval = 8 * 3600;
				break;
			case Xts::Util::UTCW09:
				timezoneInterval = 9 * 3600;
				break;
			case Xts::Util::UTCW10:
				timezoneInterval = 10 * 3600;
				break;
			case Xts::Util::UTCW11:
				timezoneInterval = 11 * 3600;
				break;
			case Xts::Util::UTCW12:
				timezoneInterval = 12 * 3600;
				break;
			default:
				break;
			}
			return timezoneInterval;
		}

		XTimeAdapter::XTimeAdapter(const XTime& tomTime)
			:x_tomTime(tomTime)
		{
			XTime2IceTime();
		}

		XTimeAdapter::XTimeAdapter(const IceUtil::Time& icTime)
			: x_icTime(icTime)
		{
			IceTime2XTime();
		}

		XTimeAdapter::XTimeAdapter(const Ice::Short& year, const Ice::Short& month, const Ice::Short& day,
			const Ice::Short& hour, const Ice::Short& minute, const Ice::Short& second, 
			const Ice::Short& milisec, const Ice::Short& microsec)
		{
			struct tm c_time;
			c_time.tm_year = year - 1900;
			c_time.tm_mon = month - 1;
			c_time.tm_mday = day;
			c_time.tm_hour = hour;
			c_time.tm_min = minute;
			c_time.tm_sec = second;

			time_t c_utc_time = mktime(&c_time);
			x_icTime = IceUtil::Time::seconds(c_utc_time);
			IceUtil::Time miliS = IceUtil::Time::milliSeconds(milisec);
			IceUtil::Time microS = IceUtil::Time::microSeconds(microsec);
			x_icTime += miliS;
			x_icTime += microS;
			IceTime2XTime();
		}

		XTimeAdapter::XTimeAdapter(const Ice::Short& year, const Ice::Short& month, const Ice::Short& day,
			const Ice::Short& hour, const Ice::Short& minute, const Ice::Short& second,
			const Ice::Short& milisec, const Ice::Short& microsec, const Ice::Long& timezoneInterval)
		{
			Ice::Long localtimeInterval;
			if (!GetLocalTimezoneInterval(localtimeInterval))
			{
				throw "Can't retrieve local timezone.";
			}

			struct tm c_time;
			c_time.tm_year = year - 1900;
			c_time.tm_mon = month - 1;
			c_time.tm_mday = day;
			c_time.tm_hour = hour;
			c_time.tm_min = minute;
			c_time.tm_sec = second;

			time_t c_utc_time = mktime(&c_time) + timezoneInterval - localtimeInterval;
			x_icTime = IceUtil::Time::seconds(c_utc_time);
			IceUtil::Time miliS = IceUtil::Time::milliSeconds(milisec);
			IceUtil::Time microS = IceUtil::Time::microSeconds(microsec);
			x_icTime += miliS;
			x_icTime += microS;
			IceTime2XTime();
		}

		XTimeAdapter::XTimeAdapter(const XTimezoneDateTime& xdtTime)
		{
			Ice::Long localtimeInterval;
			if (!GetLocalTimezoneInterval(localtimeInterval))
			{
				throw "Can't retrieve local timezone.";
			}

			struct tm c_time;
			c_time.tm_year = xdtTime.Year() - 1900;
			c_time.tm_mon = xdtTime.Month() - 1;
			c_time.tm_mday = xdtTime.Day();
			c_time.tm_hour = xdtTime.Hour();
			c_time.tm_min = xdtTime.Minute();
			c_time.tm_sec = xdtTime.Second();

			time_t c_utc_time = mktime(&c_time) + xdtTime.TimezoneInterval() - localtimeInterval;
			x_icTime = IceUtil::Time::seconds(c_utc_time);
			IceUtil::Time miliS = IceUtil::Time::milliSeconds(xdtTime.Milisec());
			IceUtil::Time microS = IceUtil::Time::microSeconds(xdtTime.Microsec());
			x_icTime += miliS;
			x_icTime += microS;
			IceTime2XTime();
		}


		XTimeAdapter::~XTimeAdapter()
		{
		}

		void XTimeAdapter::IceTime2XTime()
		{
			x_tomTime.UtcTicks = x_icTime.toMicroSeconds();
		}

		void XTimeAdapter::XTime2IceTime()
		{
			x_icTime = IceUtil::Time::microSeconds(x_tomTime.UtcTicks);
		}

		XTimezoneDateTime XTimeAdapter::ToXTimezoneDateTime(const Ice::Long& timezoneInterval)
		{
			Ice::Long localtimeInterval;
			if (!GetLocalTimezoneInterval(localtimeInterval))
			{
				throw "Can't retrieve local timezone.";
			}

			time_t secondTicks = x_icTime.toSeconds();
			time_t timezoneSecTicks = secondTicks - timezoneInterval + localtimeInterval;
			tm c_time; 
			localtime_s(&c_time, &timezoneSecTicks);

			Ice::Long milisecTicks = x_icTime.toMilliSeconds();			

			IceUtil::Time secIceTime = IceUtil::Time::seconds(secondTicks);
			IceUtil::Time milisecIceTime = IceUtil::Time::milliSeconds(milisecTicks);
			
			Ice::Long milisecInterval = (milisecIceTime - secIceTime).toMilliSeconds();
			Ice::Long microsecInterval = (x_icTime - milisecIceTime).toMicroSeconds();

			XTimezoneDateTime xdtTime(c_time.tm_year + 1900, c_time.tm_mon + 1, c_time.tm_mday,
				c_time.tm_hour, c_time.tm_min, c_time.tm_sec, milisecInterval, microsecInterval, timezoneInterval);
			return xdtTime;			
		}

		XTimezoneDateTime XTimeAdapter::ToXTimezoneDateTime(XTimeZone timezone)
		{
			Ice::Long timezoneInterval = XTimezoneDateTime::GetTimeZoneInterval(timezone);
			return ToXTimezoneDateTime(timezoneInterval);
		}

		bool XTimeAdapter::GetLocalTimezoneInterval(Ice::Long& localTimezoneInterval)
		{
			if (x_isLocalTimezoneSet)
			{
				localTimezoneInterval = x_localTimezoneInterval;
				return true;
			}

			long interval;
			errno_t ret = _get_timezone(&interval);
			if (ret == 0)
			{
				x_localTimezoneInterval = interval;
				x_isLocalTimezoneSet = true;
				localTimezoneInterval = x_localTimezoneInterval;
				return true;
			}

			return false;
		}

		Ice::Long XTimeAdapter::x_localTimezoneInterval = 0;
		bool XTimeAdapter::x_isLocalTimezoneSet = false;
	}
}


